package com.mspbots.rule.queue;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mspbots.api.RestServerException;
import com.mspbots.api.client.CoreClient;
import com.mspbots.api.service.MessagesService;
import com.mspbots.api.service.TenantConfigurationService;
import com.mspbots.api.service.TenantRuleService;
import com.mspbots.api.service.TenantUserMappingService;
import com.mspbots.cw.request.TenantRuleDTO;
import com.mspbots.cw.request.TriggerEscalationDTO;
import com.mspbots.rule.exceptions.BaseRule;
import com.mspbots.rule.queue.producer.MessageProducer;
import lombok.extern.slf4j.Slf4j;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.ObjectUtils;

import java.time.Duration;
import java.util.Map;

import static com.mspbots.rule.config.RuleConfiguration.REDIS_KEY_PREFIX_TENANT;
import static java.time.temporal.ChronoUnit.SECONDS;

/**
 * @ClassName com.mspbots.rule.queue.timeentry.BaseTrigger
 * @Description TODO
 * @Author Jun
 * @Date 2019/8/30 18:38
 * @Version 1.0
 **/
@Slf4j
public abstract class BaseQueue {

    protected TriggerEscalationDTO triggerEscalationDTO;
    protected TenantRuleDTO tenantRuleDTO;
    protected RulesEngine rulesEngine = new DefaultRulesEngine();

    @Autowired
    protected TenantRuleService tenantRuleService;
    @Autowired
    protected MessagesService messagesService;
    @Autowired
    protected TenantUserMappingService tenantUserMappingService;
    @Autowired
    protected TenantConfigurationService tenantConfigurationService;
    @Autowired
    protected MessageProducer messageProducer;
    @Autowired
    protected CoreClient coreClient;
    @Autowired
    protected ObjectMapper objectMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    /**
     * @return boolean if null: false
     * @Author Jun
     * @Description TODO
     * @Date 2019/9/19 15:40
     * @Param [ruleName, tenantId]
     **/
    protected boolean checkRule(String ruleName, Long tenantId) {
        Map<String, Object> ruleParams = Map.of("tenantId", tenantId, "enable", true, "name", ruleName);
//        log.info("tenantId_{} enable_{} name_{}",tenantId,"true",ruleName);
        this.tenantRuleDTO = this.coreClient.get("/tenant/rule/detail", ruleParams, TenantRuleDTO.class).block(Duration.of(5, SECONDS));

        if (ObjectUtils.isEmpty(this.tenantRuleDTO)) {
            log.error("tenant_{} check rule [{}] is null", tenantId, ruleName);
            return false;
        }

        String enable = stringRedisTemplate.opsForValue().get(REDIS_KEY_PREFIX_TENANT + tenantId + ":" + this.tenantRuleDTO.getRuleId() + "_enable");
        if (!Boolean.valueOf(enable)) {
            log.info("tenant [{}] rule [{}] [{}] enable [{}]", tenantId, ruleName, tenantRuleDTO.getRuleId(), enable);
        }
        return Boolean.valueOf(enable);
    }


    @Async
    protected void onRule(String ruleName, Long tenantId) {
        try {
            if (checkRule(ruleName, tenantId)) {
                Rules rules = new Rules();
                Class clazz = Class.forName(tenantRuleDTO.getClassName());
                BaseRule instance = (BaseRule) clazz.getDeclaredConstructor().newInstance();
                instance.init(tenantRuleDTO, messageProducer, messagesService, tenantUserMappingService,
                        tenantConfigurationService, coreClient, objectMapper);
                instance.setStringRedisTemplate(stringRedisTemplate);
                rules.register(instance);
                Facts facts = new Facts();
                facts.put(BaseRule.FACT, tenantId);
                rulesEngine.fire(rules, facts);

            }
        } catch (Exception e) {
            log.error("trigger [{}] fire error : {}", ruleName, e.getMessage());
            e.printStackTrace();
        }

    }

    public static class TenantRuleNotFoundException extends RestServerException {

        public TenantRuleNotFoundException(String message) {
            this(1000, message);
        }

        TenantRuleNotFoundException(int code, String msg) {
            super(code, msg);
        }
    }

}
